package jk.framework.spring.cloud.canary.loadbalancer.configure;


import jk.framework.canary.core.CanaryConfigure;
import jk.framework.canary.core.CanaryMgt;
import jk.framework.canary.core.engine.CanaryPublishEngine;
import jk.framework.canary.core.engine.DefaultCanaryPublishEngine;
import jk.framework.canary.core.mather.DefaultVersionMatcher;
import jk.framework.canary.core.mather.VersionMatcher;
import jk.framework.canary.core.repository.VersionInfoRepository;
import jk.framework.canary.core.rule.*;
import jk.framework.spring.cloud.canary.loadbalancer.comonpent.DefaultLoadBalanceRouteContextFactory;
import jk.framework.spring.cloud.canary.loadbalancer.comonpent.LoadBalanceRouteContextFactory;
import jk.framework.spring.cloud.canary.loadbalancer.comonpent.SpringCloudVersionMetaDataWriterListener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.ConditionalOnDiscoveryEnabled;
import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClientSpecification;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author cuichao
 */
@Configuration
@ConditionalOnDiscoveryEnabled
@ConditionalOnProperty(prefix ="canary", value = "enable", havingValue = "true", matchIfMissing = true )
@EnableConfigurationProperties(CurrentApiVersionProperties.class)
public class CanaryPublishAutoConfigure implements InitializingBean {

    @Autowired
    private LoadBalancerClientFactory loadBalancerClientFactory;


    @Override
    public void afterPropertiesSet() throws Exception {
        init();
    }

    private void init(){
        List<LoadBalancerClientSpecification> specifications = Collections.singletonList(
                new LoadBalancerClientSpecification("default.canary.LoadBalancer", new Class[]{CanaryLoadBalancerConfigure.class})
        );
        loadBalancerClientFactory.setConfigurations(specifications);
    }

    @Bean
    @ConditionalOnMissingBean(LoadBalanceRouteContextFactory.class)
    public LoadBalanceRouteContextFactory loadBalanceRouteContextFactory(){
        return new DefaultLoadBalanceRouteContextFactory();
    }

    @Bean
    @ConditionalOnMissingBean(VersionMatcher.class)
    public VersionMatcher canaryVersionMatcher(){
        return new DefaultVersionMatcher();
    }


    @Bean
    @ConditionalOnMissingBean(RouteRuleChain.class)
    public CanaryPublishEngine canaryPublishEngine(RouteRuleChain ruleChain,VersionMatcher matcher){
        return new DefaultCanaryPublishEngine(ruleChain,matcher);
    }

    @Bean
    @ConditionalOnMissingBean(RouteRuleChain.class)
    public RouteRuleChain canaryRuleChain(ObjectProvider<List<RouteRule>> ruleObjectProvider){
        List<RouteRule> ifUnique = ruleObjectProvider.getIfUnique(ArrayList::new);
        return new StaticInitRuleChain(ifUnique);
    }



    @Bean
    @ConditionalOnMissingBean(CanaryMgt.class)
    public CanaryMgt canaryMgt(
            CanaryPublishEngine engine,
            RouteRuleChain ruleChain,
            VersionInfoRepository versionInfoRepository,
            VersionMatcher matcher
    ){
        CanaryConfigure configure = new CanaryConfigure();
        configure.setPublishEngine(engine);
        configure.setVersionMatcher(matcher);
        configure.setRuleChain(ruleChain);
        configure.setVersionInfoRepository(versionInfoRepository);
        CanaryMgt.init(configure);
        return CanaryMgt.getInstance();
    }



    @Bean
    public SpringCloudVersionMetaDataWriterListener versionMetaDataWriterListener(){
        return  new SpringCloudVersionMetaDataWriterListener();
    }



}
